package DramCore
{
	import flash.display.MovieClip;
	import flash.events.TimerEvent;
	import flash.events.Event;
	import flash.utils.Timer;
	import DramScript.ScriptLauncher;
	
	import mx.core.Application;
	import mx.core.UIComponent;
	import DramScript.IScriptable;
	import utils.Trace;
	import DramScript.ExecuteCommandResult;
	
	public class Thing extends UIComponent implements IScriptable
	{
		public var _animCount:Number;
		protected var _game:ScriptLauncher;
	    protected var _oldUIC:UIComponent;
	    public var _symbolName:String;
       	protected var _mc:MovieClip;
  		private var _classLoader:ClassLoader;
  		
		protected var _xSquare:int;
		protected var _ySquare:int;
		// Don't process commands when _paused == true
		protected var _isPaused:Boolean;
		// Name of current animation.
		public var _animName:String;
		private var _animParamArr:Array;
		private var _animTimer:Timer;
		// Move variables
		private var _atDestination:Boolean;
		private var _pathXArr:Array; // Set of points to move along
		private var _pathYArr:Array;
		private var _destinationX:Number;
		private var _destinationY:Number;
		// Scale variables
		private var _scaleTicks:int; // How many ticks to reach scale goal
		private var _scaleXTarget:Number = 100;
		private var _scaleYTarget:Number = 100;
		private var _atScale:Boolean =true;
		// Rotation variables
		private var _atRotation:Boolean;
		private var _rotationIncrement:int; // How many ticks to reach scale goal
		private var _rotationTicks:int;
		private var _rotationTarget:int;
		// Alpha variables
		private var _atAlpha:Boolean;
		private var _alphaTicks:int;
		private var _alphaTarget:int;
		public var _centerView:Boolean; // keep this in the center of the parent?

		private var _z:Number;
		
//		protected var DB_DramVars:AllVars; // Public for Serializability???
		// The coord of the visual origin
			
		public  function Thing( name:String , swfName:String, defaultSymbolName:String  ) {
			super( );
			this.showIt( swfName, defaultSymbolName );
			this._isPaused = false;
			this._z = 0;
			this.rotation = 0;
			this._centerView = false;
			var initObj:Object = undefined;
			this.name = name;
			this._oldUIC = null;
			this._game = Application.application._game;

			// Animation
			this._animCount = 0;
			this._animName = "";
			this._animParamArr = new Array();
			// Translation
			this._atDestination = true;
			this._pathXArr = new Array() ; // Set of points to move along
			this._pathYArr = new Array();
			this._destinationX= 0;
			this._destinationY = 0;
			// Scale
			this._atScale = true;
			this._scaleTicks = 0;
			this._scaleXTarget = 100;
			this._scaleYTarget = 100;
			// Rotation
			this._atRotation = true;
			this._rotationIncrement = 0; // degrees to rotate every turn
			this._rotationTicks = 0;
			this._rotationTarget = 0;
			// Alpha
			this._atAlpha = true;
			this._alphaTicks = 0;
			this._alphaTarget = 0;
		}
		// executeCommand( ----------------------------------------------------
		public function executeCommand(target:String, command:String, paramArr:Array):ExecuteCommandResult {
			Trace.execCommTrace("Thing",target,command,paramArr);

			var ecr:ExecuteCommandResult = new ExecuteCommandResult( );
			if( this._isPaused )
				return ecr;
			switch( command.toUpperCase() ){
				case "SCALE": // Scale, seconds 
					startScale((paramArr[1]*this.scaleX)/100,(paramArr[1]*this.scaleY)/100,paramArr[2]);
					break;
				case "SCALETO":   // Scale, Scale, seconds 
					startScale(paramArr[1],paramArr[1],paramArr[2]);
					break;
				case "STRETCHTO":   // xScale, yScale, seconds 
					startScale(paramArr[1],paramArr[2],paramArr[3]);
					break;
				case "STRETCH":   // xScale, yScale, seconds 
					startScale((paramArr[1]*this.scaleX)/100,(paramArr[2]*this.scaleY)/100,paramArr[3]);
					break;
				case "MOVETO":    
					startMove(paramArr[1],paramArr[2],paramArr[3], paramArr[4]);
					break;
				// Move ThingName, Relative-x, y, [z], [seconds]
				case "MOVE":
					// Add params to current position
					paramArr[0] += this.x;
					paramArr[1] += this.y;
					paramArr[2] += this.z;
					startMove(paramArr[1],paramArr[2],paramArr[3], paramArr[4]); 
					break;
				case "ALPHA":
					startAlpha(paramArr[1],paramArr[2]);
				break;
				case "ROTATE":
					startRotate(paramArr[1],paramArr[2]);
				break;
				case "ROTATETO":
					startRotateTo(paramArr[1],paramArr[2],paramArr[3]);
				break;
				case "ANIMATE":
					// animName, animCount
						startAnimation(paramArr[1], paramArr[2]);
					break;
				case "SAYS":
					// Add thing position and bounds for UI talk balloon drawing  
					paramArr.push(this.x);
					paramArr.push(this.y);
//					paramArr.push(getBounds(this._stage_mc)); // Bounding rect of thing
//					resultArr = _game.DramUI.executeCommand(script,command,paramArr);
				break;
				case "WAIT":
					if( this.isMoving() ){ // Still animating
							ecr = new ExecuteCommandResult("WAIT"); 
					}  else {
					}
				break;
				default:
					trace new Error("Thing can't handle command: "+command);
				break;
			} 
			return ecr;
		} // executeCommand
		public function isMoving():Boolean {
			return( (!this._atDestination)   // Still travelling
						|| (!this._atScale)		// Still scaling
						|| (!this._atAlpha)		// Still alphaing
						|| (!this._atRotation)  // Still rotating
						|| (this._animCount) )
		}
		// tick() -----------------------------------------
		// Do action, driven by setInterval by game 
		public function tickTock(event:TimerEvent):void {
			if(!this._atDestination) {
				if(this._pathXArr.length >0 ) {
					this.x = Number(this._pathXArr.pop());
					this.y = Number(this._pathYArr.pop());
					if( this._centerView ){
						this.parent.x = 400 - this.x ;
						this.parent.y = 300 - this.y;
					}
				} else {
					this._atDestination = true;
				}
			}
			if(!(this._atScale)) {
				if(this._scaleTicks-- >1 ) {
					this.scaleX += (this._scaleXTarget-this.scaleX)/this._scaleTicks;
					this.scaleY += (this._scaleYTarget-this.scaleY)/this._scaleTicks;
				} else {
					this.scaleX = this._scaleXTarget;
					this.scaleY = this._scaleYTarget;
					this._atScale = true;
				}
			} 
			if(!this._atAlpha) {
				if(this._alphaTicks-- >1 ) { 
					this.alpha += (this._alphaTarget - this.alpha)/this._alphaTicks;
				} else {
					this.alpha = this._alphaTarget;
					this._atAlpha = true;
				}
			}
			if(!this._atRotation) {
				if(this._rotationTicks-- >1 ) { 
					this.rotation += this._rotationIncrement;
				} else {
					this.rotation = this._rotationTarget;
					this._atRotation = true;
				}
			}
		} // tick
		public function doPause():void {
//			trace("this.doPause()");
			this._isPaused = true;
		}
		public function unPause():void {
//			trace("this.unPause()");
			this._isPaused = false;
		}
 		public function showIt( swfName:String, symbolName:String ):void {
         	var uic:UIComponent = new UIComponent();
         	swfName = Application.application._assetPath + "/graphics/swfs/" + swfName;
			this._classLoader = new ClassLoader(swfName, symbolName );
			this._classLoader.addEventListener(Event.COMPLETE, create);
				
		}
 		private function create(e:Event):void
		{
			var cl:Class = this._classLoader.getClass();
			addChild(new cl());
			this._classLoader.removeEventListener( Event.COMPLETE, create );
		}   		
  // Move playhead to frame labeled name_st -----------------------------------------------------
		// Override startAnimate in the first frame of an thing symbol
		// for Non-timeline/frame-label animation
		private function startAnimation(animName:String, animCount:int ):void {
//			Trace.myTrace("Thing.startAnimation: "+animName );
			
			this._animName = animName;
			this._animCount = animCount;
//			this.animateFrames( 0 );
		} 
		
		//startRotate() --------------------------------------
		private function startRotate(rotateDegrees:Number,seconds:Number):void {
			this._atRotation = false;
			this._rotationTarget = this.rotation + rotateDegrees;
			this._rotationTicks = seconds*this._game.TICKSPERSECOND;
			this._rotationIncrement = rotateDegrees/this._rotationTicks;
		} //startRotate()
		
		//startRotateto() --------------------------------------
		private function startRotateTo( rotateTarget:Number, clockwise_st:String, seconds:Number):void {
			var rotateDegrees:Number; // Number of degrees to rotate + or -
			this._atRotation = false;
			this._rotationTarget = rotateTarget;
			rotateDegrees = this.rotation - rotateTarget;
			this._rotationTicks = seconds*this._game.TICKSPERSECOND;
			if(clockwise_st == "cw") { // Rotate clockwise
				rotateDegrees = Math.abs(rotateDegrees);
			} else { // counterclockwise
				rotateDegrees = Math.abs(rotateDegrees)*-1;
			}
			this._rotationIncrement = rotateDegrees/this._rotationTicks;
		} //startRotateTo()
		
		// startScale() ----------------------------
		private function startScale(xScale:Number,yScale:Number,seconds:Number):void {
	//trace("startScale: "+xScale+", "+yScale+", "+seconds);
			this._scaleXTarget = xScale;
			this._scaleYTarget = yScale;
			this._scaleTicks = seconds*this._game.TICKSPERSECOND;
			if(this._scaleTicks <1) this._scaleTicks = 1; // XXX honk honk
			this._atScale = false;
		} // startScale()
		
		// startAlpha() ----------------------------
		private function startAlpha(alphaTarget:Number,seconds:Number):void {
	//trace("startScale: "+xScale+", "+yScale+", "+seconds);
			this._alphaTarget = alphaTarget;
			this._alphaTicks = seconds*this._game.TICKSPERSECOND;
			if(this._alphaTicks <1) this._alphaTicks = 1; // XXX honk honk
			this._atAlpha = false;
		} // startAlpha()
		
		// Set destination and calculate path---------------------------------------------------------
		// XXX uses wonky path calc. Increment mean number of interpolated points
		private function startMove (xTarget:Number, yTarget:Number, zTarget:Number, seconds:Number ):void {
			var pathX:Number = 0;
			var pathY:Number = 0;
			var xInc:Number = 0; // Incremental X movement
			var yInc:Number = 0;
			var inc:Number = seconds*this._game.TICKSPERSECOND;
			
			this._pathXArr = new Array();
			this._pathYArr = new Array();
			
			if(inc <1) inc = 1; // XXX honk honk
			this._destinationX = xTarget;
			this._destinationY = yTarget;
			this._atDestination = false;

			xInc = (xTarget - this.x)/inc;
			yInc = (yTarget - this.y)/inc;
			
			for( var i:int = 0; i < inc ; i++) {
				this._pathXArr.push(this._destinationX - xInc*i);
				this._pathYArr.push(this._destinationY - yInc*i);
			}
		} // startMove
		// accessors -------------------------------------------------------------------------
		public function get z():Number {
			return this._z;
		}
		public function set z( z:Number ):void {
			this._z = z;
		}
	}
}